{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# YOLOv11 推理 Notebook\n",
    "下面演示如何加载单张图片并逐步推理"
   ],
   "id": "e99ae77ef3e52c24"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 1. 环境准备 & 导入包\n",
    "导入必要的 Python 包"
   ],
   "id": "3befd14469c2a41a"
  },
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "from ultralytics import YOLO            # YOLOv11 模型接口\n",
    "import matplotlib.pyplot as plt         # 用于图像展示\n",
    "import cv2                              # 用于图像读取与绘制\n",
    "import os                               # 用于文件和路径操作\n",
    "import matplotlib                       # 用于配置字体\n",
    "\n",
    "# 配置 matplotlib 支持中文，避免中文标签或标题出现缺失\n",
    "matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体\n",
    "matplotlib.rcParams['axes.unicode_minus'] = False    # 解决负号 '-' 显示为方块的问题\n",
    "\n",
    "print(\"环境准备完成：依赖包已导入，已配置中文字体支持\")\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 2. 加载模型\n",
    "从训练输出目录加载最佳权重"
   ],
   "id": "972cb4b78cdc9913"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "model = YOLO('runs/train/exp/weights/best.pt')  # 加载训练好的 .pt 文件\n",
    "print(f\"模型加载完成。\\n类别名称：{model.names}\")"
   ],
   "id": "8c77451bb0a0b384",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 3. 读取并展示输入图片\n",
    "- 指定单张图片路径，确认文件存在\n",
    "- 用 OpenCV 读取 BGR 图像并转换为 RGB\n",
    "- 使用 matplotlib 展示"
   ],
   "id": "576f14ebaf4d265d"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "img_path = 'datasets/weeds/images/train/02981.jpg'  # 修改为你的图片路径\n",
    "assert os.path.exists(img_path), f\"错误：未找到图片：{img_path}\"\n",
    "\n",
    "# 读取图像（BGR 格式）\n",
    "img_bgr = cv2.imread(img_path)\n",
    "print(f\"加载图像，原始形状 (高, 宽, 通道)：{img_bgr.shape}\")\n",
    "\n",
    "# 转换为 RGB 以便 matplotlib 正确显示\n",
    "img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)\n",
    "plt.figure(figsize=(6,6))\n",
    "plt.axis('off')\n",
    "plt.title('输入图像')\n",
    "plt.imshow(img_rgb)\n",
    "plt.show()"
   ],
   "id": "40916da82c318964",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 4. 对单张图片执行推理\n",
    "- 使用 `model.predict` 获取 `Results` 对象列表\n",
    "- 设置 `save=False` 和 `verbose=False` 关闭文件保存与进度输出"
   ],
   "id": "92317ec2eb8d6770"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "results = model.predict(\n",
    "    source=img_path,    # 输入单张图片路径\n",
    "    imgsz=640,          # 调整推理尺寸\n",
    "    save=False,         # 不将结果保存为新文件\n",
    "    verbose=False       # 不输出额外日志\n",
    ")\n",
    "print(f\"推理完成。结果数量：{len(results)}\")\n",
    "\n",
    "# 获取第一个结果对象\n",
    "res = results[0]\n",
    "print(f\"第一个结果对象信息：{res}\")"
   ],
   "id": "a529f34954900869",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 5. 可视化推理结果\n",
    "- 从 `res.boxes` 提取边界框坐标、置信度与类别\n",
    "- 分别调用 `.xyxy`, `.conf`, `.cls` 属性以避免解包错误\n",
    "- 在图像上绘制矩形框及文字标签"
   ],
   "id": "49c513fa3865a816"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 第一部分：提取数据",
   "id": "f8f1c2e80e677e4f"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "# 提取数据：边界框坐标 (Nx4)、置信度 (N)、类别索引 (N)\n",
    "xyxy = res.boxes.xyxy.cpu().numpy()    # 形状 (N,4)\n",
    "conf = res.boxes.conf.cpu().numpy()    # 形状 (N,)\n",
    "cls  = res.boxes.cls.cpu().numpy()     # 形状 (N,)\n",
    "names = model.names                   # 类别名称字典\n",
    "print(f\"检测到 {xyxy.shape[0]} 个目标\")"
   ],
   "id": "7d52b0230f6c973b",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 第二部分：在图像上绘制检测框与标签",
   "id": "70dc9f4e533f33f6"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "# 复制原图用于绘制\n",
    "img_show = img_rgb.copy()\n",
    "for (x1, y1, x2, y2), c, cl in zip(xyxy, conf, cls):\n",
    "    x1, y1, x2, y2 = map(int, (x1, y1, x2, y2))\n",
    "    label = f\"{names[int(cl)]}: {c:.2f}\"\n",
    "    # 绘制绿色矩形框\n",
    "    cv2.rectangle(img_show, (x1, y1), (x2, y2), (0,255,0), 2)\n",
    "    # 计算文字背景尺寸并绘制\n",
    "    (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)\n",
    "    cv2.rectangle(img_show, (x1, y1-th-4), (x1+tw, y1), (0,255,0), -1)\n",
    "    cv2.putText(img_show, label, (x1, y1-4), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,0,0), 1)\n",
    "\n",
    "# 显示结果图\n",
    "plt.figure(figsize=(6,6))\n",
    "plt.axis('off')\n",
    "plt.title('推理结果可视化')\n",
    "plt.imshow(img_show)\n",
    "plt.show()"
   ],
   "id": "e92323acaa31929d",
   "outputs": [],
   "execution_count": null
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
